package zorm

/*
	增，删，搜，改

*/
import (
	"bytes"
	"database/sql"
	"encoding/gob"
	"encoding/json"
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"time"
	"unsafe"
)

//功能 外部经常会用到ID这个字段，所以单独取出来，供外部调用
func GetInterfaceId(obj interface{}) int64 {
	o := reflect.ValueOf(obj)
	for o.Kind() == reflect.Ptr {
		o = o.Elem()
	}
	obj2 := o.FieldByName("Id").Interface()
	if t, ok := obj2.(int); ok == true {
		return int64(t)
	} else if t, ok := obj2.(int32); ok == true {
		return int64(t)
	} else if t, ok := obj2.(int64); ok == true {
		return t
	} else {
		panic("无法识别的类型")
	}
}

//功能 外部经常会用到ID这个字段，所以单独取出来，供外部调用
func SetInterfaceId(obj interface{}, id interface{}) {
	o := reflect.ValueOf(obj)
	for o.Kind() == reflect.Ptr {
		o = o.Elem()
	}
	newid := int64(0)
	if t, ok := id.(int); ok == true {
		newid = int64(t)
	} else if t, ok := id.(int32); ok == true {
		newid = int64(t)
	} else if t, ok := id.(int64); ok == true {
		newid = t
	} else {
		panic(fmt.Sprintf("无法识别的ID类型:%T", id))
	}
	o.FieldByName("Id").SetInt(newid)
}

//功能 按ID搜索某个模块
//如果domain为空,则搜索ID号
func (z *ZDB) First(uid *SUser, model interface{}, domain string, context map[string]interface{}) error {
	if len(domain) == 0 {
		domain = fmt.Sprintf("[Id,=,%d]", GetInterfaceId(model))
	}
	rev, err := z.Query(uid, model, domain, []string{}, []string{}, 0, 1, context)
	if err != nil {
		return err
	}
	if len(rev) == 0 {
		return sql.ErrNoRows
	} else {
		src := reflect.ValueOf(model)
		if src.Kind() != reflect.Ptr {
			panic("First:传入参数必须为指针")
		} else {
			if err := deepCopy(model, rev[0]); err != nil {
				return err
			}
		}
		return nil
	}
}
func (z *ZDB) Count(uid *SUser, model interface{}, domain string, context map[string]interface{}) (int, error) {
	var sqls string
	if z.isDebug == true {
		st := time.Now()
		defer func() {
			if len(sqls) > 0 {
				fmt.Printf("ORM %08s %f\t %s\r\n", time.Now().Format("15:04:05"), time.Now().Sub(st).Seconds(), sqls)
			}
		}()
	}

	minfo, err := GetTableInfo(model)
	if err != nil {
		panic(err)
	}
	sqls = "SELECT count(*) "
	tabName := GetTableName(model)
	if tabName == "pd0" || tabName == "d0" {
		panic("")
	}
	sqls += " FROM " + tabName + " "
	if t := z.GetModelDomain(uid, minfo.Name, "AtQuery"); len(t) != 0 { //获取筛选
		if len(domain) != 0 {
			domain += "&"
		}
		domain += t
	}
	if len(domain) != 0 {
		dm := &DOMAIN{Domain: []rune(domain), Context: context, Model: minfo.Name, uid: uid, Zdb: z}
		if err := dm.Parse(); err != nil {
			return 0, err
		} else {
			if len(dm.Sql) != 0 {
				sqls += " WHERE " + dm.Sql
			}
		}
	}
	rows, err := z.Db.Query(sqls)
	if err != nil {
		return 0, err
	}
	defer rows.Close()
	var ret int
	for rows.Next() {
		if err := rows.Scan(&ret); err != nil {
			return 0, err
		}
		return ret, nil
	}
	panic("未获取到Count")
}
func (z *ZDB) Query2(uid *SUser, model interface{}, domain string, context map[string]interface{}) ([]interface{}, error) {
	return z.Query(uid, model, domain, []string{}, []string{}, 0, 65535, context)
}

//功能 进行数据查询
//参数
//     table 	使用的是哪个表(已经注册的表)
//     uid   	SUser中的Id
//     domain 	格式化搜索条件
//     fields   返回的字段列表
//     orderby  排序
//     limit    页大小
//     offset   起始位置
//     context  其它数据,配合搜索
//返回 行数据
//注意
func (z *ZDB) Query(uid *SUser, model interface{}, domain string, fields []string, orderby []string, offset int, limit int, context map[string]interface{}) ([]interface{}, error) {
	var sqls string
	if z.isDebug == true {
		st := time.Now()
		defer func() {
			if len(sqls) > 0 {
				fmt.Printf("ORM %08s %f\t %s\r\n", time.Now().Format("15:04:05"), time.Now().Sub(st).Seconds(), sqls)
			}
		}()
	}

	//核心在这里
	sqls = "SELECT "
	minfo, err := GetTableInfo(model)
	if err != nil {
		return nil, err
	}
	var revvals []interface{} //返回的数据
	var scancols []string     //实际搜索的列,结构中的名称
	var revcoltype []*SFields
	if len(fields) == 0 {
		for _, v := range minfo.Cols {
			fields = append(fields, v)
		}
	}
	dbkey := m_key[z.dbtype]
	区分符 := dbkey["字段区分符号"]
	for i, v := range fields {
		if i != 0 {
			sqls += ","
		}
		fieldtype, err := GetModelField(minfo.Name, v)
		if err != nil {
			return nil, errors.New("未操作到模块:" + minfo.Name + "下的字段:" + v)
		}
		sqls += 区分符 + fieldtype.Field + 区分符
		obj := GetType(fieldtype.Type)
		revvals = append(revvals, &obj) //添加到列表中
		scancols = append(scancols, v)
		revcoltype = append(revcoltype, fieldtype)
	}
	tabName := GetTableName(model)
	if tabName == "d0" {
		panic("")
	}
	sqls += " FROM " + tabName + " "
	if t := z.GetModelDomain(uid, minfo.Name, "atquery"); len(t) != 0 { //获取筛选
		if len(domain) != 0 {
			domain += "&"
		}
		domain += t
	}
	if len(domain) != 0 {

		dm := &DOMAIN{Domain: []rune(domain), Context: context, Model: minfo.Name, uid: uid, Zdb: z}
		if err := dm.Parse(); err != nil {
			panic(err)
		} else {
			if len(dm.Sql) != 0 {
				sqls += " WHERE " + dm.Sql
			}
		}
	}
	if len(orderby) != 0 { //添加排序
		sqls += " ORDER BY "
		for i, v := range orderby {
			if i != 0 {
				sqls += ","
			}
			sp := strings.Split(v, " ")
			if len(sp) > 2 {
				panic("")
			}
			fieldtype, err := GetModelField(minfo.Name, sp[0])
			if err != nil {
				return nil, errors.New("未操作到模块:" + minfo.Name + "下的字段:" + v)
			}
			sqls += fieldtype.Field
			if len(sp) == 2 {
				ascordesc := strings.ToLower(sp[1])
				if ascordesc == "asc" {
					sqls += " ASC"
				} else if ascordesc == "desc" {
					sqls += " DESC"
				} else {
					panic("")
				}
			}
		}
	}
	if limit <= 0 {
		fmt.Println("Limit 为0，重置为10")
		limit = 10
	}
	sqls += " Limit " + strconv.Itoa(limit)   //LIMIT
	sqls += " OFFSET " + strconv.Itoa(offset) //OFFSET

	rows, err := z.Db.Query(sqls)
	if err != nil {
		//panic(err.Error() + "\r\n" + sqls)
		return nil, err
	}
	defer rows.Close()
	var ret []interface{} //返回的数据
	for rows.Next() {
		if err := rows.Scan(revvals...); err != nil {
			return nil, err
		}
		newobjp := reflect.New(reflect.TypeOf(minfo.YZ).Elem())
		newobj := newobjp.Elem()
		for i, _ := range scancols { //将数据转换成map
			cov, err := ConvInterface2Type(*(revvals[i].(*interface{})), revcoltype[i].TypeObj) //获取数据
			if err != nil {
				panic(fmt.Sprintln("字段名:["+fields[i]+"]赋值出错:"+err.Error(), "ID:", GetInterfaceId(newobjp.Interface())))
			}
			newobj.FieldByName(revcoltype[i].Name).Set(reflect.ValueOf(cov))
		}
		ret = append(ret, newobjp.Interface())
	}
	return ret, nil
}

func (z *ZDB) UpdateAny(strptr interface{}, fields []string) (int, error) {
	var sqls string
	if z.isDebug == true {
		st := time.Now()
		defer func() {
			if len(sqls) > 0 {
				fmt.Printf("ORM %08s %f\t %s\r\n", time.Now().Format("15:04:05"), time.Now().Sub(st).Seconds(), sqls)
			}
		}()
	}
	sqls = "UPDATE " + GetTableName(strptr) + " SET "
	if len(fields) == 0 {
		panic("更新的字段必须存在!")
	}
	dbkey := m_key[z.dbtype]
	区分符 := dbkey["字段区分符号"]
	minfo, err := GetTableInfo(strptr)
	if err != nil {
		panic(err)
	}
	for i, v := range fields {
		if i != 0 {
			sqls += ","
		}
		s, err := z.GetStructField(strptr, v)
		if err != nil {
			return 0, err
		}

		fieldtype, err := GetModelField(minfo.Name, v)
		if err != nil {
			return 0, errors.New("未操作到模块:" + minfo.Name + "下的字段:" + v)
		}

		sqls += 区分符 + fieldtype.Field + 区分符 + "=" + s
	}
	if _, err := z.Db.Exec(sqls); err != nil {
		panic(fmt.Sprintf("%s, SQL:%s", err.Error(), sqls))
	}
	return 0, nil
}

//功能 进行数据更新
//参数
//     table 表名
//     args  更新的字段  字段名必须为结构中字段
//     ids   更新哪个ID，如果为空，则更新所有
//返回
//     int  影响多少字段
//     error 出错信息
func (z *ZDB) Update(uid *SUser, strptr interface{}, fields []string, ids ...int64) (int, error) {
	var sqls string
	if z.isDebug == true {
		st := time.Now()
		defer func() {
			if len(sqls) > 0 {
				fmt.Printf("ORM %08s %f\t %s\r\n", time.Now().Format("15:04:05"), time.Now().Sub(st).Seconds(), sqls)
			}
		}()
	}

	minfo, err := GetTableInfo(strptr)
	if err != nil {
		return 0, err
	}
	if len(fields) == 0 {
		fields = minfo.Cols //后来修改，如果不指定修改的字段，则全部更新
	}
	sqls = ""
	dbkey := m_key[z.dbtype]
	区分符 := dbkey["字段区分符号"]
	for _, v := range fields {
		if v == "Id" { //ID不更新
			continue
		}
		if len(sqls) != 0 {
			sqls += ","
		}
		ftype, ok := minfo.Fields[v]
		if ok == false {
			panic("模块:" + minfo.Name + " 未知字段:" + v)
		}
		s, err := z.GetStructField(strptr, ftype.Name)
		if err != nil {
			panic(err)
			//return 0, err
		}
		sqls += 区分符 + ftype.Field + 区分符 + "=" + s
	}
	if len(ids) == 0 {
		sqls += fmt.Sprintf(" WHERE id =%d", reflect.ValueOf(strptr).Elem().FieldByName("Id").Interface())
	} else {
		sqls += " WHERE id in("
		for i, v := range ids {
			if i != 0 {
				sqls += ","
			}
			sqls += fmt.Sprintf("%d", v)
		}
		sqls += ")"
	}
	sqls = "UPDATE " + GetTableName(strptr) + " SET " + sqls
	if _, err := z.Db.Exec(sqls); err != nil {
		panic(fmt.Sprintf("执行出错:%s, SQL:%s\r\n", err.Error(), sqls))
	}
	return 0, nil
}

//功能 进行数据更新
//参数
//     table 表名
//     args  删除的条件  字段名必须为结构中字段
//     ids   更新哪个ID，如果为空，则更新所有
//返回
//     int  影响多少字段
//     error 出错信息
func (z *ZDB) Delete(uid int, strptr interface{}, ids ...int) (int, error) {
	var sqls string
	if z.isDebug == true {
		st := time.Now()
		defer func() {
			if len(sqls) > 0 {
				fmt.Printf("ORM %08s %f\t %s\r\n", time.Now().Format("15:04:05"), time.Now().Sub(st).Seconds(), sqls)
			}
		}()
	}
	sqls = "DELETE FROM " + GetTableName(strptr)
	if len(ids) == 0 {
		sqls += fmt.Sprintf(" WHERE id =%d", reflect.ValueOf(strptr).Elem().FieldByName("Id").Interface())
	} else {
		sqls += " WHERE id in("
		for i, v := range ids {
			if i != 0 {
				sqls += ","
			}
			sqls += strconv.Itoa(v)
		}
		sqls += ")"
	}
	if _, err := z.Db.Exec(sqls); err != nil {
		panic(fmt.Sprintf("%s, SQL:%s", err.Error(), sqls))
	}
	return 0, nil
}

//功能 进行数据更新
//参数
//     table 表名
//     obj   更新的结构
//返回
//     error 出错信息
//注意
//     obj中的ID将自动赋值为最新值
func (z *ZDB) Insert(uid *SUser, obj interface{}, context map[string]interface{}) error {
	var sqls string
	if z.isDebug == true {
		st := time.Now()
		defer func() {
			if len(sqls) > 0 {
				fmt.Printf("ORM %08s %f\t %s\r\n", time.Now().Format("15:04:05"), time.Now().Sub(st).Seconds(), sqls)
			}
		}()
	}
	minfo, err := GetTableInfo(obj)
	if err != nil {
		panic(err)
	}
	cols := ""
	vals := ""
	isreturnid := true //设置是否返回ID
	dbkey := m_key[z.dbtype]
	区分符 := dbkey["字段区分符号"]
	for _, v := range minfo.Cols {
		o, err := z.GetStructField(obj, v) //将数据转为指定类型的字符串
		if err != nil {
			panic(err)
		}
		if v == "Id" {
			if o == "0" { //值为0时不存储　，如果不为0，则存储
				continue
			}
			isreturnid = false

		}
		if len(cols) != 0 {
			cols += ","
			vals += ","
		}
		fs, err := GetModelField(minfo.Name, v) //获取字段属性
		if err != nil {
			panic(err)
		}
		cols += 区分符 + fs.Field + 区分符
		vals += o
	}
	sqls = "INSERT INTO " + GetTableName(obj) + " (" + cols + ") VALUES (" + vals + ")"
	switch z.dbtype {
	case "postgres":
		sqls += dbkey["_insert_retid"]
		rows, err := z.Db.Query(sqls)
		if err != nil {
			panic(err)
		}
		defer rows.Close()
		id := 0
		for rows.Next() {
			if err := rows.Scan(&id); err != nil {
				panic(err)
			}
			break
		}
		if isreturnid == true {
			SetInterfaceId(obj, id) //设置返回的ID
		}
	case "mysql":
		res, err := z.Db.Exec(sqls)
		if err != nil {
			return err
		}
		if isreturnid == true {
			id, err := res.LastInsertId()
			if err != nil {
				return err
			}
			if id == 0 {
				panic("新建的ID不可能为0")
			}
			SetInterfaceId(obj, id) //设置返回的ID
		}
	default:
		panic("")
	}
	return nil
}

//功能 根据指定列搜索数据，如果存在，则更新，如果不存在，则创建
//注意 更新时，可能会更新多个数据列
func (z *ZDB) InsertOrUpdate(uid *SUser, obj interface{}, compfields []string, updatefields []string, context map[string]interface{}) (int, error) {
	domain := ""
	ref := reflect.ValueOf(obj)
	for ref.Kind() == reflect.Ptr {
		ref = ref.Elem()
	}
	minfo, err := GetTableInfo(obj)
	if err != nil {
		panic(err)
	}
	for _, v := range compfields {
		tp, ok := minfo.Fields[v]
		if ok == false {
			return 0, errors.New("未识别的字段:" + v)
		}
		if s, err := z.getStructFileByPtr(ref.FieldByName(v).Interface(), tp); err != nil {
			return 0, err
		} else {
			domain += fmt.Sprintf("[%s,=,%s]", v, s)
		}
	}
	revs, err := z.Query(uid, obj, domain, []string{}, []string{}, 0, 1, context)
	if err != nil {
		return 0, err
	}
	if len(revs) == 0 { //没有发现，则创建
		if err := z.Insert(uid, obj, context); err != nil {
			return 0, err
		}
		return 0, nil
	}
	var ids []int64
	for _, v := range revs { //搜索到的可能是多个数据，所以全部要更新
		ids = append(ids, GetInterfaceId(v))
	}
	//到了这里就是已经存在了
	if len(updatefields) == 0 {
		return z.Update(uid, obj, minfo.Cols, ids...)
		//return z.Update(uid, obj, updatefields, )
		//return z.Insert(uid, obj, context)
	} else {
		return z.Update(uid, obj, updatefields, ids...)
	}
}

type sliceHeader struct {
	Data unsafe.Pointer
	Len  int
	Cap  int
}
type emptyInterface struct {
	typ  *struct{}
	word unsafe.Pointer
}

//功能 将一个interface类型，转为指定的类型,返回的类型为 golang类型
//参数
//    ojb 源类型
//    tp  目标类型
func ConvInterface2Type(srcobj interface{}, decobj interface{}) (interface{}, error) {
	//srcref := reflect.ValueOf(srcobj) //源类型
	decref := reflect.ValueOf(decobj) //目标类型
	/*	if srcobj == nil {                //如果数据为NULL，则返回一个数据备份
			return reflect.New(reflect.TypeOf(decobj)).Elem().Interface(), nil
		}
	*/
	switch decref.Kind() {
	case reflect.Bool:
		if srcobj == nil {
			return false, nil
		} else if t, ok := srcobj.(bool); ok == true {
			return t, nil
		} else if t, ok := srcobj.([]uint8); ok == true {
			if len(t) == 0 || t[0] == 48 {
				return false, nil
			}
			return true, nil
		} else if t, ok := srcobj.(string); ok == true {
			if t == "true" {
				return true, nil
			} else if t == "false" {
				return false, nil
			}
		}
	case reflect.Uint8:
		if srcobj == nil {
			return uint8(0), nil
		} else if t, ok := srcobj.(uint8); ok == true {
			return t, nil
		} else if t, ok := srcobj.([]uint8); ok == true {
			ret, err := strconv.ParseUint(string(t), 10, 8)
			if err != nil {
				return nil, err
			} else {
				return uint8(ret), nil
			}
		} else if t, ok := srcobj.(string); ok == true {
			ret, err := strconv.ParseUint(t, 10, 8)
			if err != nil {
				return nil, err
			} else {
				return uint8(ret), nil
			}
		}
	case reflect.Int16:
		if srcobj == nil {
			return int16(0), nil
		} else if t, ok := srcobj.([]uint8); ok == true {
			ret, err := strconv.ParseInt(string(t), 10, 16)
			if err != nil {
				return nil, err
			} else {
				return int16(ret), nil
			}
		} else if t, ok := srcobj.(float64); ok == true {
			return uint16(t), nil
		} else if t, ok := srcobj.(string); ok == true {
			ret, err := strconv.ParseInt(t, 10, 16)
			if err != nil {
				return nil, err
			} else {
				return int16(ret), nil
			}
		}
	case reflect.Uint16:
		if srcobj == nil {
			return uint16(0), nil
		} else if t, ok := srcobj.([]uint8); ok == true {
			ret, err := strconv.ParseUint(string(t), 10, 16)
			if err != nil {
				return nil, err
			} else {
				return uint16(ret), nil
			}
		} else if t, ok := srcobj.(float64); ok == true {
			return uint16(t), nil
		} else if t, ok := srcobj.(string); ok == true {
			ret, err := strconv.ParseUint(t, 10, 16)
			if err != nil {
				return nil, err
			} else {
				return uint16(ret), nil
			}
		}
	case reflect.Int32:
		ret := int32(0)
		if srcobj == nil {
			return ret, nil
		} else if t, ok := srcobj.(int); ok == true {
			return int32(t), nil
		} else if t, ok := srcobj.(string); ok == true {
			if t1, err := strconv.Atoi(t); err == nil {
				return int32(t1), nil
			}
		} else if t, ok := srcobj.([]uint8); ok == true {
			if t0, err := strconv.Atoi(string(t)); err != nil {
				return ret, err
			} else {
				return int32(t0), err
			}
		} else if t, ok := srcobj.(int64); ok == true {
			return int32(t), nil
		} else if t, ok := srcobj.(float64); ok == true { //map[string]int   值会被翻译成float
			return int32(t), nil
		}
	case reflect.Uint32:
		ret := uint32(0)
		if srcobj == nil {
			return ret, nil
		} else if t, ok := srcobj.(int); ok == true {
			return uint32(t), nil
		} else if t, ok := srcobj.(string); ok == true {
			if t1, err := strconv.Atoi(t); err == nil {
				return uint32(t1), nil
			}
		} else if t, ok := srcobj.([]uint8); ok == true {
			if t0, err := strconv.Atoi(string(t)); err != nil {
				return ret, err
			} else {
				return uint32(t0), err
			}
		} else if t, ok := srcobj.(int64); ok == true {
			return uint32(t), nil
		} else if t, ok := srcobj.(float64); ok == true { //map[string]int   值会被翻译成float
			return uint32(t), nil
		}
	case reflect.Int:
		if srcobj == nil {
			return int(0), nil
		} else if t, ok := srcobj.(int); ok == true {
			return t, nil
		} else if t, ok := srcobj.(string); ok == true {
			if t1, err := strconv.Atoi(t); err == nil {
				return t1, nil
			}
		} else if t, ok := srcobj.([]uint8); ok == true {
			return strconv.Atoi(string(t))
		} else if t, ok := srcobj.(int64); ok == true {
			return int(t), nil
		} else if t, ok := srcobj.(float64); ok == true { //map[string]int   值会被翻译成float
			return int(t), nil
		}
	case reflect.Int64:
		if srcobj == nil {
			return int64(0), nil
		} else if t, ok := srcobj.(int64); ok == true {
			return t, nil
		} else if t, ok := srcobj.(string); ok == true {
			if t1, err := strconv.ParseInt(t, 10, 64); err == nil {
				return t1, nil
			}
		} else if t, ok := srcobj.([]uint8); ok == true {
			if t1, err := strconv.ParseInt(string(t), 10, 64); err == nil {
				return t1, nil
			} else {
				return int64(0), nil
			}
		} else if t, ok := srcobj.(int64); ok == true {
			return t, nil
		} else if t, ok := srcobj.(float64); ok == true { //map[string]int   值会被翻译成float
			return int64(t), nil
		}
	case reflect.Float32:
		if srcobj == nil {
			return float32(0), nil
		} else if t, ok := srcobj.(float32); ok == true {
			return t, nil
		} else if t, ok := srcobj.(string); ok == true {
			if t1, err := strconv.ParseFloat(t, 64); err == nil {
				return float32(t1), nil
			}
		} else if t, ok := srcobj.(float64); ok == true {
			return float32(t), nil
		} else if t, ok := srcobj.([]uint8); ok == true {
			ret, err := strconv.ParseFloat(string(t), 32)
			if err != nil {
				return nil, err
			}
			return float32(ret), nil
		}
	case reflect.Float64:
		if srcobj == nil {
			return float64(0), nil
		} else if t, ok := srcobj.(float64); ok == true {
			return t, nil
		} else if t, ok := srcobj.(string); ok == true {
			if t1, err := strconv.ParseFloat(t, 64); err == nil {
				return t1, nil
			}
		} else if t, ok := srcobj.([]uint8); ok == true {
			ret, err := strconv.ParseFloat(string(t), 64)
			if err != nil {
				return nil, err
			}
			return ret, nil
		} else if t, ok := srcobj.(int); ok == true {
			return float64(t), nil
		}
	case reflect.String:
		if srcobj == nil {
			return "", nil
		} else if t, ok := srcobj.(string); ok == true {
			return t, nil
		} else if t, ok := srcobj.([]uint8); ok == true {
			return string(t), nil
		} else if t, ok := srcobj.(int); ok == true {
			return strconv.Itoa(t), nil
		}
	case reflect.Slice:
		ret := reflect.New(reflect.TypeOf(decobj)).Elem() //申请类型
		value := reflect.New(reflect.TypeOf(ret.Interface()).Elem()).Elem()
		if srcobj == nil {
			return ret.Interface(), nil
		} else if t, ok := srcobj.([]uint8); ok == true {
			s := string(t)
			sp := strings.Split(s, ",")
			for _, v := range sp {
				if len(v) == 0 {
					continue
				}
				val, err := ConvInterface2Type([]byte(v), value.Interface())
				if err != nil {
					return nil, err
				}
				ret = reflect.Append(ret, reflect.ValueOf(val))
			}
			return ret.Interface(), nil
		}
	case reflect.Struct:
		ret := reflect.New(decref.Type()).Elem() //申请类型
		if srcobj == nil {
			return ret.Interface(), nil
		} else if _, ok := decobj.(time.Time); ok == true { //不能返回src也不能用dec，涉及到内存共用问题，所以一定要生成新变量
			if srcobj == nil {
				return time.Parse("2006-01-02 15:04:05", "2000-01-01 00:00:00")
			} else if t, ok := srcobj.(time.Time); ok == true {
				return time.Parse("2006-01-02 15:04:05", t.Format("2006-01-02 15:04:05"))
			} else if t, ok := srcobj.(string); ok == true {
				if ret, err := time.Parse("2006-01-02 15:04:05", t); err != nil {
					panic(err)
				} else {
					return ret, nil
				}
			}
		} else if t, ok := srcobj.([]uint8); ok == true {
			id, err := strconv.Atoi(string(t))
			if err != nil {
				panic(err)
			}

			ret.FieldByName("Id").SetInt(int64(id))
			return ret.Interface(), nil
		} else if t, ok := srcobj.(int); ok == true { //源类型是一个数字，而目标类型是一个结构，这一定是MANY2ONE
			ret.FieldByName("Id").SetInt(int64(t))
			return ret.Interface(), nil
		} else if t, ok := srcobj.(int64); ok == true { //源类型是一个数字，而目标类型是一个结构，这一定是MANY2ONE
			ret.FieldByName("Id").SetInt(t)
			return ret.Interface(), nil
		}
	case reflect.Map:
		ret := reflect.New(reflect.TypeOf(decobj)).Elem() //申请类型
		mapret := reflect.MakeMap(ret.Type())             //申请新的MAP空间
		if srcobj == nil {
			return mapret.Interface(), nil
		} else if t, ok := srcobj.([]uint8); ok == true {
			var jsonmap map[string]interface{}
			if len(t) <= 1 { //如果没有数据,则直接返回
				return ret.Interface(), nil
			}
			if err := json.Unmarshal(t, &jsonmap); err != nil {
				return nil, err
			}
			if jsonmap == nil { //如果输出本身就是NULL，那么就直接返回吧
				return ret.Interface(), nil
			}

			key := reflect.TypeOf(ret.Interface()).Key()
			value := reflect.TypeOf(ret.Interface()).Elem()

			for k, v := range jsonmap {
				k0 := reflect.New(key).Elem()
				v0 := reflect.New(value).Elem()
				k1, err := ConvInterface2Type(k, k0.Interface())
				if err != nil {
					return nil, err
				}
				v1, err := ConvInterface2Type(v, v0.Interface())
				if err != nil {
					return nil, err
				}
				mapret.SetMapIndex(reflect.ValueOf(k1), reflect.ValueOf(v1))
			}
			//	fmt.Printf("输出的JSON为：%T,%v,,目标Key类型:%T 目标值:%v\r\n", jsonmap, jsonmap, mapret.Interface(), mapret)
			return mapret.Interface(), nil
		}
	case reflect.UnsafePointer:
		//fmt.Printf("UnsafePointer:%T,%v\r\n", decref, decref)

	}
	return nil, errors.New(fmt.Sprintf("源无法转换:src类型:%T 值: %v,目标类型:%T,目标KIND:%d", srcobj, srcobj, decobj, int(decref.Kind())))
}

//功能 设置一个字段的值
//参数
//     strptr 结构的指针，必须是指针
//     field  字段名称
//     obj    字段的值
func SetStructField(strptr interface{}, srcfield string, obj interface{}) error {
	minfo, err := GetTableInfo(strptr)
	if err != nil {
		panic(err)
	}
	fs, err := GetModelField(minfo.Name, srcfield) //获取字段类型
	if err != nil {
		return err
	}
	obj2, err := ConvInterface2Type(obj, fs) //  类型转换
	if err != nil {
		return errors.New("字段:" + srcfield + err.Error())
	}
	//fmt.Printf("开始对%v 的%s进行赋值:%v\r\n", strptr, srcfield, obj)
	fval := reflect.ValueOf(strptr).Elem().FieldByName(srcfield) //获取字段值
	switch fs.Type {
	case TYPE_UINT8:
		fval.SetUint(uint64(obj2.(uint8)))
	case TYPE_INT:
		fval.SetInt(int64(obj2.(int)))
	case TYPE_INT64:
		fval.SetInt(obj2.(int64))
	case TYPE_STRING:
		fval.SetString(obj2.(string))
	case TYPE_BOOL:
		fval.SetBool(obj2.(bool))
	case TYPE_DATETIME:
		//deepCopy(fval.Interface)
		t0 := fval.Addr().Interface().(*time.Time)
		*t0 = obj2.(time.Time)
	case TYPE_FLOAT64:
		fval.SetFloat(obj2.(float64))
	/*case TYPE_JSON:
	t := obj2.(map[string]interface{})
	for k, v := range t {
		fval.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v))
	}
	*/
	case TYPE_MANY2MANY:
		obj3, err := GetTableInterface(fs.Relation)
		if err != nil {
			return err
		}
		fobj3 := reflect.ValueOf(obj3)
		SetInterfaceId(fobj3, obj2)
		//fobj3.Elem().FieldByName("Id").SetInt(int64(obj2.(int32)))
		fval.Set(fobj3)
		t := obj2.(map[string]interface{})
		for k, v := range t {
			fval.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v))
		}
	case TYPE_MANY2ONE:
		obj3, err := GetTableInterface(fs.Relation)
		if err != nil {
			return err
		}
		fobj3 := reflect.ValueOf(obj3)
		//fmt.Printf("生成的新实例:%T,%v\r\n", obj3, obj3)
		SetInterfaceId(fobj3, obj2)
		//fobj3.Elem().FieldByName("Id").SetInt(int64(obj2.(int32)))
		fval.Set(fobj3)
	case TYPE_JSON:
		fval.Set(reflect.ValueOf(obj).Elem())
	default:
		panic("未处理的类型:" + strconv.Itoa(fs.Type))
	}
	return nil
}
func deepCopy(dst interface{}, src interface{}) error {
	var buf bytes.Buffer
	if err := gob.NewEncoder(&buf).Encode(src); err != nil {
		return err
	}
	return gob.NewDecoder(bytes.NewBuffer(buf.Bytes())).Decode(dst)
}

//功能  从指定指针位置取出一个指定类型的数据,转换成字符型，用于存储到数据库中
func (z *ZDB) getStructFileByPtr(fieldptr interface{}, fs *SFields) (string, error) {
	switch fs.Type {
	case TYPE_UINT8:
		return strconv.FormatUint(uint64(fieldptr.(uint8)), 10), nil
	case TYPE_UINT16:
		return strconv.FormatUint(uint64(fieldptr.(uint16)), 10), nil
	case TYPE_INT16:
		return strconv.FormatInt(int64(fieldptr.(int16)), 10), nil
	case TYPE_INT32:
		return strconv.FormatInt(int64(fieldptr.(int32)), 10), nil
	case TYPE_INT:
		return strconv.Itoa(fieldptr.(int)), nil
	case TYPE_INT64:
		return strconv.FormatInt(fieldptr.(int64), 10), nil
	case TYPE_STRING:
		s := fieldptr.(string) //特殊字符替换
		return "'" + 转义(s) + "'", nil
	case TYPE_BOOL:
		return strconv.FormatBool(fieldptr.(bool)), nil
	case TYPE_FLOAT64:
		if t, ok := fieldptr.(float64); ok == true {
			return strconv.FormatFloat(t, 'f', 1, 64), nil
		} else if t, ok := fieldptr.(float32); ok == true {
			return strconv.FormatFloat(float64(t), 'f', 1, 32), nil
		}
	case TYPE_DATETIME:
		t := fieldptr.(time.Time)
		if t.Year() == 0001 {
			t = time.Now()
		}
		switch z.dbtype {
		case "postgres":
			t = t.Add(time.Hour * -8) //减去8小时
		}
		return "'" + t.Format("2006-01-02 15:04:05") + "'", nil
	case TYPE_MANY2MANY: //MANY2MANY 一定是两个结构体
		fval := reflect.ValueOf(fieldptr)
		if fval.Kind() == reflect.Ptr {
			fval = fval.Elem()
		}
		ret := "',"
		for i := 0; i < fval.Len(); i++ {
			fval2 := fval.Index(i)
			switch fval2.Kind() {
			case reflect.Ptr, reflect.Struct, reflect.Map:
				ret += fmt.Sprintf("%d,", GetInterfaceId(fval2.Interface()))
			case reflect.String:
				ret += fmt.Sprintf("%s,", 转义(fval2.Interface().(string)))
			default:
				ret += fmt.Sprintf("%v,", fval2.Interface())
			}

		}
		ret += "'"
		return ret, nil
		/*加速访问，不使用反射
		tn := GetSmailTableName(fs.Relation)
		tf, ok := fmTables[tn]
		if ok == false {
			panic("未发现的表:" + fs.Relation)
		}
		idoffset := tf.Fields["id"].Offset
		header := (*sliceHeader)(unsafe.Pointer(fieldptr)) //获取切片头地址

		dptr := header.Data //这是第一个数据的首地址,以后取数据全以这里开始
		for i := 0; i < header.Len; i++ {
			ret += strconv.Itoa(*((*int)(unsafe.Pointer(uintptr(dptr) + idoffset)))) + ","
		}
		ret += "'"
		return ret, nil*/
	case TYPE_MANY2ONE:
		fval := reflect.ValueOf(fieldptr)
		/*fmt.Printf("MANY2ONE:%T,%v\r\n", fieldptr, fieldptr)
		if fval.IsNil() == true {
			return "0", nil
		}*/
		if fval.Kind() == reflect.Ptr { //判断是否为指针
			fval = fval.Elem()
		}
		return fmt.Sprintf("%d", fval.FieldByName("Id").Interface()), nil
	/*case TYPE_JSON:
	bys, err := json.Marshal(fieldptr)
	if err != nil {
		return "", err
	}
	return "'" + string(bys) + "'", nil*/
	/*自己写的，没测试
	if strings.Index(fs.Relation, "[]") != -1 { //	JSON的下面是切片
		s, err := json2Str(fieldptr, fs.Relation)
		if err != nil {
			return "", err
		}
		return "'" + s + "'::jsonb", nil
	}
	*/
	case TYPE_JSON:
		if fieldptr == nil {
			return "''", nil
		} else {
			bys, err := json.Marshal(fieldptr)
			if err != nil {
				return "", err
			}
			return "'" + 转义(string(bys)) + "'", nil
		}
	}
	panic("无法识别的类型:" + strconv.Itoa(fs.Type))
}

//功能 获取一个结构下的字段,并转为数据库格式
//参数
//    strptr 结构的指针,必须是指针
//    srcfield  字段名称 必须与字段名称一样
//返回
func (z *ZDB) GetStructField(strptr interface{}, srcfield string) (string, error) {
	minfo, err := GetTableInfo(strptr)
	if err != nil {
		panic(err)
	}
	val := reflect.ValueOf(strptr)
	if val.Kind() == reflect.Ptr {
		val = val.Elem()
	}
	filetype, err := GetModelField(minfo.Name, srcfield)
	if err != nil {
		return "", err
	}
	return z.getStructFileByPtr(val.FieldByName(srcfield).Interface(), filetype)
}
func 转义(s string) string {
	s = strings.Replace(s, "\\", "\\\\", -1)
	s = strings.Replace(s, "'", "\\'", -1)
	s = strings.Replace(s, "\"", "\\\"", -1)
	return s
}
